package utilidades;

import java.util.LinkedList;
import espacio.ConocedorDeAeropuerto;
import errores.ErrorDireccionInvalida;

public class Trayectoria {
	
	protected LinkedList<Posicion> colaDePosiciones;
	protected double longitudDePaso;
	protected Posicion posicionActual;
	protected Posicion posicionAnterior;
	
	/* ******* Constructor de la clase Trayectoria ****** */
	public Trayectoria(Posicion posicionInicial,Posicion posicionFinal) {
		//La longitud de Paso esta predefinida 1 por predeterminado
		longitudDePaso = 1;
		
		//La posicion anterior es una posicion en la direccion inversa entre 
		// inicial y final
		Direccion direccion = new Direccion(posicionFinal,posicionInicial);
		posicionAnterior = posicionInicial.obtenerPosicionEnDireccion(direccion);
		posicionActual = posicionInicial;
		//La posicion Final empiesa siendo la primera Posicion del la  Trayectoria
		colaDePosiciones = new LinkedList<Posicion>();		
		encolarPosicionEnTrayectoria(posicionFinal);
	}
	
	//Obtiene el siguiente punto al cual debe dirigirse
	public Posicion getSiguientePunto(){
		Posicion siguientePosicion;
		
		Posicion posicionCorreccionDeTrayectoria = ConocedorDeAeropuerto.obtenerPuntoEnCasoDeViolacionDeLimite(this);
		
		if (posicionCorreccionDeTrayectoria!=null){
			
			this.vaciarTrayectoria();
			siguientePosicion = posicionCorreccionDeTrayectoria;
		}
		
		else if(this.estaVacia()){
			siguientePosicion = obtenerSiguientePuntoSinTrayectoria();	
		}
		else {
			siguientePosicion = obtenerSiguientePuntoConTrayectoria();
		}
		this.actualizarPosiciones(siguientePosicion);
		return siguientePosicion;
	}
	
	//Obtiene la direccion al siguiente punto de la trayectoria
	private Direccion getDireccionAlSiguientePunto(){
		try{
		return (new Direccion(posicionActual,colaDePosiciones.getFirst()));
		} catch (ErrorDireccionInvalida e) {			
			return Direccion.getDireccionAleatoria();
		}
	}
	
	//Obtiene la direccion que esta siguiendo la trayectoria
	public Direccion getDireccion(){
		try{
			return new Direccion(posicionAnterior,posicionActual);
		} catch (ErrorDireccionInvalida e) {
			return Direccion.getDireccionAleatoria();
		}
	}
	
	public Posicion getPosicionActual(){
		
		return posicionActual;
	}

	//Actualisa las posiciones anteriores por la nuevas
	private void actualizarPosiciones(Posicion nuevaPosicion) {
		posicionAnterior = posicionActual;
		posicionActual = nuevaPosicion;
	}
	
	//Obtiene el siguiente punto si la cola de Posiciones esta vacia
	protected Posicion obtenerSiguientePuntoSinTrayectoria(){
		Direccion direccion = getDireccion();
		Posicion siguientePosicion = 
				posicionActual.obtenerPosicionEnDireccionYdistancia(direccion,longitudDePaso);
		return siguientePosicion;
	}
	
	//Obtiene el siguiente punto si la cola de Posiciones no esta vacia	
	private Posicion obtenerSiguientePuntoConTrayectoria(){
		
		Posicion siguientePosicion;
		
		Posicion posicionAuxiliar = posicionActual;
		
		Direccion direccion = getDireccionAlSiguientePunto();
		Posicion movimiento = new Posicion(direccion.getX()*longitudDePaso
				, direccion.getY()*longitudDePaso);
		
		double distanciaMaxima = 
				colaDePosiciones.getFirst().distancia(posicionActual);						
		
		double distanciaDeMovimiento = movimiento.getNorma();
		
		if (distanciaDeMovimiento<distanciaMaxima) {						
			
			siguientePosicion = posicionAuxiliar.trasladar(movimiento);
			
		
		} else {
			siguientePosicion = this.desencolarPosicionEnTrayectoria();}
		
		return siguientePosicion;
	}
	
	private boolean estaVacia(){
		
		return (colaDePosiciones.size()==0);
	}
	
	/* *** Funciones para agregar y quitar posiciones a la trayecyoria *** */
	
	public void encolarPosicionEnTrayectoria(Posicion unaPosicion){
		colaDePosiciones.addLast(unaPosicion);
	}
	
	protected Posicion desencolarPosicionEnTrayectoria(){
		
		return colaDePosiciones.removeFirst();
	}
	
	public void vaciarTrayectoria(){
		
		colaDePosiciones.clear();
	}
	
	/* ****** Funciones para cambiar velocidad ***** */
	
	public void acelerar(double escalar){
		longitudDePaso *= escalar;
	}
	
}
